package org.reliablesource.prism.ui.viewers;

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.reliablesource.prism.core.IPrismAnnotation;
import org.reliablesource.prism.core.IPrismScreen;
import org.reliablesource.prism.core.IPrismTutorial;
import org.reliablesource.prism.core.plugin.PrismCorePlugin;
import org.reliablesource.prism.ui.custom.BalloonWindow;
import org.reliablesource.prism.ui.plugin.PrismPlugin;

/**
 * 
 * AnimationViewer.java <br>
 * Copyright (c) 2006, Reliable Source, Inc. All Rights Reserved<br><br>
 * 
 * Created on: Oct 5, 2006<br>
 * 
 * @author Dennis Park 
 *         <a href="mailto:dennis.park@gmail.com">dennis.park@gmail.com</a>
 * 
 */

public class AnimationViewer extends Viewer {
	public final static String CONTAINER_ID = 
			"org.reliablesource.prism.ui.workbench.views.animationview";
	
	final static int DELAY = 18;
	final static int PAUSE = 1800;
	final static int X_OFFSET = -4;
	final static int Y_OFFSET = -1;

	final private Display display;
	final private Image pointer;
	final private AudioClip clickSound;

	private volatile int imageDataIndex;
	private GC offScreenImageGC;
	private volatile Image offScreenImage;

	private int xa, ya, xb, yb;
	private int drawX, drawY;
	private ImageData[] imageDataArray;
	private Canvas animationCanvas;

	private Thread animateThread;
	private IPrismTutorial tutorial;
	private volatile IPrismScreen currentScreen;

	private volatile List<Point> polyLinePath;
	private ImageData imageData;
	private ToolBar toolBar;

	private volatile ToolItem play;
	private volatile ToolItem stop;
	private volatile ToolItem reload;
	private volatile ToolItem forward;
	private volatile ToolItem backward;
	private volatile ToolItem pause;
	private volatile static Boolean paused;

	private volatile boolean indexChanged;

	private volatile boolean playAll;
	protected Composite contentComposite;
	protected BalloonWindow window;
	
	public AnimationViewer(){
		super();
		display = Display.getDefault();
		
		clickSound = Applet.newAudioClip(PrismPlugin.getDefault().getBundle()
				.getResource("sounds/CLICKERX.WAV"));
		pointer = PrismPlugin.getImageDescriptor("icons/pointer.gif")
				.createImage();
		
		playAll = false;
		playAll = true;
		
		paused = Boolean.FALSE;
		indexChanged = true;
	}
	
	public void init() throws ViewerInitException{
		if(false)
			throw new ViewerInitException();
	}
	
	/**
	 * 	This method plays the default tutorial in the navigation viewer.
	 *
	 */
	public void startAnimation() {
		
		// Load full set of screens - on demand pagination might be necessary.
		if (tutorial == null)
			tutorial = ((IPrismTutorial) PrismCorePlugin.getDefault().getModel().getChild(0));

		tutorial = ((IPrismTutorial) PrismCorePlugin.getDefault().getModel().getChild(0));
		int nScreens = tutorial.getChildListSize();
		imageDataArray = new ImageData[nScreens];

		for (int i = 0; i < nScreens; i++) {
			IPrismScreen _screen = (IPrismScreen) tutorial.getChild(i);
				imageDataArray[i] = PrismPlugin.getDefault().readScreen(_screen).getImageData();
		}
 
		xa = 0; ya = 0; xb = 0; yb = 0;

		try {
			if (imageDataArray.length > 0) {
				if (animateThread == null) {
					animateThread = new Thread("Animation") {
						public void run() {

							Image image = null;
							
							// Create an off-screen image to draw on, and fill
							// it
							// with the shell background.
							offScreenImage = new Image(display,
									imageDataArray[0].width,
									imageDataArray[0].height);
							offScreenImageGC = new GC(offScreenImage);
							
							imageData = imageDataArray[0];
							offScreenImageGC.fillRectangle(0, 0,
									imageData.width, imageData.height);

							try {
								Thread thisThread = Thread.currentThread();
								while (this == thisThread) {
									if (indexChanged || playAll) {
										// Handling users' selection

										// reset the imgDataIdx
										 if(!playAll)
											 imageDataIndex = 0;

										 if(imageDataIndex <= tutorial.getChildListSize())
											currentScreen = (IPrismScreen) tutorial	.getChild(imageDataIndex);
										else
											imageDataIndex = tutorial.getChildSequence(currentScreen);
										
										// Create the first image, draw it on
										// the
										// off-screen image.
										imageData = imageDataArray[imageDataIndex];
										
										if (image != null
												&& !image.isDisposed())
											image.dispose();
										image = new Image(display, imageData);

										offScreenImageGC.drawImage(image, 0, 0,
												imageData.width,
												imageData.height, imageData.x,
												imageData.y, imageData.width,
												imageData.height);

										// Loop through the imgs, creating &
										// drawing each one on the off-screen
										// img before drawing it on the shell.

										display.syncExec(new Runnable() {
											public void run() {
												indexChanged = false;
												animationCanvas.redraw();
											}
										});
									}

									/*
									 * Determine the start point, end point, and
									 * intermediate points.
									 */

										display.asyncExec(new Runnable() {
											public void run() {
												if(window != null){
													if(window.getShell().isVisible())
														window.close();
												}
												List<IPrismAnnotation> _annotations = currentScreen.getAnnotationsList();
												int nAnnotations = _annotations.size();
												if(nAnnotations >=0){
													IPrismAnnotation _anote = currentScreen.getAnnotationsList().get(0);
													openBalloon(_anote);
												}
											}
										});
									

									// Start pt
									xa = currentScreen.getPointerStart().x;
									ya = currentScreen.getPointerStart().y;
									polyLinePath = new ArrayList<Point>();

									// Immediately add the first location to path list.
									polyLinePath.add(currentScreen.getPointerStart());

									// FIXME: Should catch an NPE and array out
									// of bounds exception. There are use cases when this can 
									//happen.  (ie. undo/redo)

									// NOTE: We want the animation behavior to
									// be able to modify its' path in real time response to the user
									// editing the path, so do not pre-calculate the size of the
									// path list.
									if (currentScreen.getPathLocationsList()
											.size() > 0) {
										
										//	Calculate
										for (int i = 0; i < currentScreen.getPathLocationsList().size(); i++) {
											
											if (indexChanged)
												break;
											
											Point bendPoint = currentScreen.getPathLocation(i);
											xb = bendPoint.x;
											yb = bendPoint.y;

											if (!((xa == xb) && (ya == yb))) {
												polyLinePath.add(bendPoint);
												drawLineBresenham(xa, ya, xb, yb);
												xa = xb;
												ya = yb;
											}
										}
										
									}

									xb = currentScreen.getPointerEnd().x;
									yb = currentScreen.getPointerEnd().y;
									
									// Bresenham's Line Drawing Algorithm
									if ((!((xa == xb) && (ya == yb)))) {
										polyLinePath.add(currentScreen.getPointerEnd());

										if (!indexChanged)
											drawLineBresenham(xa, ya, xb, yb);
										else
											polyLinePath.clear();
									}

									if (playAll) {
										// If we have just drawn the last image, repeat.
										if (imageDataIndex >= (imageDataArray.length - 1))
											imageDataIndex = 0;
										else
											// Is this supposed to happen
											// *before*
											// the above condition is checked?
											imageDataIndex++;

									}
								}
							} catch (final SWTException ex) {
								System.out
										.println("There was an error animating the screens.");
								System.err.println(ex);
							} finally {
								if (animateThread != null) {
									animateThread.interrupt();
									animateThread = null;
								}
								if (offScreenImage != null
										&& !offScreenImage.isDisposed())
									offScreenImage.dispose();
								if (image != null && !image.isDisposed())
									image.dispose();
								if (pointer != null && !pointer.isDisposed())
									pointer.dispose();
							}
						}
					};
					
					if(Display.getCurrent() == null)
						Display.getDefault().asyncExec(animateThread);
					else
						animateThread.start();
				}else if(Thread.State.TERMINATED.equals(animateThread.getState()) ){
					animateThread = null;
					startAnimation();
				}

			}
		} catch (final Exception ex) {
			System.out.println("There was an error loading the GIF");
		}
	}

	public void createViewerControl(final Composite _parent) 
		throws ViewerCreateControlException{
		if(_parent == null)
			throw new ViewerCreateControlException();
		
		contentComposite = new Composite(_parent, SWT.NONE);
		
		GridLayout layout = new GridLayout();
		contentComposite.setLayout(layout);
		
		createToolbar(contentComposite);
		animationCanvas = new Canvas(contentComposite, SWT.DOUBLE_BUFFERED);

		 String contextKey = CONTAINER_ID + "." + "AnimationCanvas";
		 PrismPlugin.getDefault().addWidget(contextKey, animationCanvas);
		 
		animationCanvas.setLayoutData(new GridData(GridData.FILL_BOTH));
		animationCanvas.addPaintListener(new PaintListener() {
			public void paintControl(final PaintEvent pe) {
				if (offScreenImage != null && !offScreenImage.isDisposed()) {
					
					if (indexChanged)
						return;

					pe.gc.drawImage(offScreenImage, 0, 0);

					if (indexChanged)
						return;
					
					pe.gc.drawImage(pointer, drawX, drawY);

					// Debugging pointer guidance logic
					if (polyLinePath != null) {
						Iterator it = polyLinePath.iterator();
						if (it.hasNext()) {
							Point pt = (Point) it.next();
							Point pt2;

							while (it.hasNext()) {
								pt2 = (Point) it.next();
								if (indexChanged)
									return;
								pe.gc.drawLine(pt.x, pt.y, pt2.x, pt2.y);
								pt = pt2;
							}
						}
					} else { // not a polyLine path
						int startX = currentScreen.getPointerStart().x;
						int startY = currentScreen.getPointerStart().y;
						int endX = currentScreen.getPointerEnd().x;
						int endY = currentScreen.getPointerEnd().y;

						if (indexChanged)
							return;
						pe.gc.drawLine(startX, startY, endX, endY);
					}
					
					// Debug statements
					// e.gc.drawText("Image #: "
					// + imageDataIndex + ": " + x + "-"
					// + y + "@@" + x2 + "-" + y2, 350,
					// 550);
				}
			}
		});
		
	}

	public void setFocus() {
		if(animationCanvas != null)
			animationCanvas.setFocus();
	}
	
	void drawLineBresenham(int x_1, int y_1, int x_2, int y_2) {
		double deltax, deltay;
		double slope;

		deltax = x_2 - x_1; // Change in x
		deltay = y_2 - y_1; // Change in y

		// Check for divide by zero
		if (deltax == 0)
			linePosSteep(x_1, y_1, x_2, y_2);
		else {
			slope = deltay / deltax;

			if (slope > 0.0) {
				if (slope > 1.0)
					linePosSteep(x_1, y_1, x_2, y_2);
				else
					linePosShallow(x_1, y_1, x_2, y_2);
			} else {
				if (slope > -1.0) {
					lineNegShallow(x_1, y_1, x_2, y_2);
				} else {
					lineNegSteep(x_1, y_1, x_2, y_2);
				}
			}
		}
	}

	void linePosShallow(int x_1, int y_1, int x_2, int y_2) {
		int dx, dy, p, twody, twodx, twodydx, twodxdy, x, y, x2, y2, xend;

		dx = Math.abs(x_1 - x_2);
		dy = Math.abs(y_1 - y_2);
		twodxdy = 2 * (dx - dy);
		twody = 2 * dy;
		twodydx = 2 * (dy - dx);
		twodx = 2 * dx;
		// NOTE: both expressions for 'p' seem to work on the test case.
		// p = twodx - dy;
		p = twody - dx;

		x = x_1;
		y = y_1;

		x2 = x_2;
		y2 = y_2;

		xend = x2;

		drawPixel(x, y, x2, y2);

		if (indexChanged)
			return;

		// ------------Capture interlude----------------
		if (paused.equals(Boolean.FALSE))
			clickSound.play();
		try {
			Thread.sleep(PAUSE);
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
		// ---------------------------------------------

		if (x < xend) {
			while (x < xend && !(indexChanged)) {
				x++;
				if (p < 0)
					p += twody;
				else {
					y++;
					p += twodydx;
				}
				drawPixel(x, y, x2, y2);
			}
		}

		/**
		 * Here we are going from a higher x1, to a lower x value, and then a
		 * lower y value to a higher one.
		 * 
		 * x1 > x2 && y1 > y2
		 * 
		 */
		else {
			// p = twodx - dy;
			while (x > xend && !(indexChanged)) {
				x--;
				if (p < 0)
					p += twody;
				else {
					y--;
					p += twodydx;
				}
				drawPixel(x, y, x2, y2);
			}
		}
	}

	void linePosSteep(int x_1, int y_1, int x_2, int y_2) {
		int dx, dy, p, twodx, twody, twodydx, twodxdy, x, y, x2, y2, yend;

		dx = Math.abs(x_1 - x_2);
		dy = Math.abs(y_1 - y_2);

		twodx = 2 * dx;
		twody = 2 * dy;
		p = twodx - dy;
		// p = twody - dx;

		twodxdy = 2 * (dx - dy);
		twodydx = 2 * (dy - dx);

		y = y_1;
		yend = y_2;
		x = x_1;
		x2 = x_2;
		y2 = y_2;

		// Vertical line
		if (x_1 == x_2) {
			if (y_2 > y_1) {
				yend = y_2;
				y = y_1;
				y2 = y_2;
				x2 = x_2;
			} else {
				yend = y_1;
				y = y_2;
			}
			for (; y <= yend; y++)
				drawPixel(x_1, y, x2, y2);
		}

		x = x_1;
		y = y_1;
		yend = y_2;

		y2 = y_2;
		x2 = x_2;

		if (x_1 != x_2) {
			drawPixel(x_1, y_1, x2, y2);

			if (indexChanged)
				return;
			// ------------Capture interlude----------------
			if (paused.equals(Boolean.FALSE))
				clickSound.play();
			try {
				Thread.sleep(PAUSE);
			} catch (InterruptedException e) {
				e.printStackTrace();
				Thread.currentThread().interrupt();
			}
			// ---------------------------------------------
			if (y < yend) {
				while (y < yend && !(indexChanged)) {
					y++;
					if (p < 0)
						p += twodx;
					else {
						x++;
						p += twodxdy;
					}
					drawPixel(x, y, x2, y2);
				}
			} else {
				while (y > yend && !(indexChanged)) {
					y--;
					if (p < 0)
						p += twodx;

					else {
						x--;
						p += twodxdy;
					}
					drawPixel(x, y, x2, y2);
				}

			}
		}
	}

	void lineNegShallow(int x_1, int y_1, int x_2, int y_2) {
		int dx, dy, p, twody, twodydx, x, y, x2, y2, xend;

		dx = Math.abs(x_2 - x_1);
		dy = Math.abs(y_2 - y_1);
		p = 2 * dy - dx;
		twody = 2 * dy;
		twodydx = 2 * (dy - dx);
		x = x_1;
		y = y_1;
		x2 = x_2;
		y2 = y_2;
		xend = x2;

		int yend = y_2;

		x = x_1;
		y = y_1;
		xend = x_2;

		y2 = y_2;
		x2 = x_2;

		drawPixel(x, y, x2, y2);

		if (indexChanged)
			return;

		// ------------Capture interlude----------------
		if (paused.equals(Boolean.FALSE))
			clickSound.play();
		try {
			Thread.sleep(PAUSE);
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
		// ---------------------------------------------

		if (x < xend) {
			while (x < xend && !(indexChanged)) {
				x++;
				if (p < 0)
					p += twody;
				else {
					y--;
					p += twodydx;
				}
				drawPixel(x, y, x2, y2);
			}
		} else {
			/**
			 * Here we are going from a higher x1, to a lower x value, and then
			 * a lower y value to a higher one.
			 * 
			 * x1 > x2 && y1 < y2
			 * 
			 */
			while (y < yend && !(indexChanged)) {
				x--;
				if (p < 0)
					p += twody;
				else {
					y++;
					p += twodydx;
				}
				drawPixel(x, y, x2, y2);
			}
		}
	}

	void lineNegSteep(int x_1, int y_1, int x_2, int y_2) {
		int dx, dy, p, twodx, twodxdy, x, y, x2, y2, yend, xend;

		dx = Math.abs(x_2 - x_1);
		dy = Math.abs(y_2 - y_1);
		twodx = 2 * dx;
		twodxdy = 2 * (dx - dy);

		p = 2 * dy - dx;
		// p = twodx - dy;
		x = x_1;
		y = y_1;

		x2 = x_2;
		y2 = y_2;

		yend = y2;
		xend = x_2;

		drawPixel(x, y, x2, y2);

		if (indexChanged)
			return;
		// ------------Capture interlude----------------
		if (paused.equals(Boolean.FALSE))
			clickSound.play();
		try {
			Thread.sleep(PAUSE);
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
		// ---------------------------------------------

		/**
		 * (x1 > x2) AND (y1 < y2)
		 */

		if (x > xend && y < yend) {
			while (y < yend && !(indexChanged)) {
				y++;
				if (p < 0)
					p += twodx;
				else {
					x--;
					p += twodxdy;
				}
				drawPixel(x, y, x2, y2);
			}

		} else {
			while (y > yend && !(indexChanged)) {
				y--;
				if (p < 0)
					p += twodx;
				else {
					x++;
					p += twodxdy;
				}
				drawPixel(x, y, x2, y2);
			}
		}
	}

	void drawPixel(int x, int y, int x2, int y2) {
		drawX = x + X_OFFSET;
		drawY = y + Y_OFFSET;

		synchronized (animateThread) {
			while (paused.equals(Boolean.TRUE)) {
				try {
					animateThread.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
					Thread.currentThread().interrupt();
				}
			}
		}

		if (indexChanged)
			return;

		display.syncExec(new Runnable() {
			public void run() {
				animationCanvas.redraw();
			}
		});

		if (indexChanged)
			return;

		// 	Animation delay
		try {
			Thread.sleep(DELAY);
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}

	/**
	 * <p>
	 * Creates the toolbar using the specified
	 * {@link org.eclipse.swt.widgets.Composite#Composite} as the parent.
	 * 
	 * <p>
	 * No actions will be associated with the toolbar object. It is a container
	 * for the toolitems.
	 * </p>
	 * 
	 * @param the
	 *            <code>parent</code> <code>Composite</code> to which the
	 *            toolbar object will be added
	 */
	private void createToolbar(final Composite parent) {
		// create the top,right justified, flat toolbar
		toolBar = new ToolBar(parent, SWT.TOP | SWT.FLAT);

		// set toolbar layout data to fill up horizontal row of its location.
		toolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		String contextKeyPrefix = CONTAINER_ID + ".AnimationCanvas.ToolBar";

		PrismPlugin.getDefault().addWidget(contextKeyPrefix, toolBar);

		backward = new ToolItem(toolBar, SWT.PUSH);
		backward.setImage(PrismPlugin.getImageDescriptor("icons/step_back.gif")
				.createImage());

		PrismPlugin.getDefault().addWidget(contextKeyPrefix + ".backward",
				backward);

		forward = new ToolItem(toolBar, SWT.PUSH);
		forward.setImage(PrismPlugin.getImageDescriptor("icons/step.gif")
				.createImage());

		PrismPlugin.getDefault().addWidget(contextKeyPrefix + ".forward",
				forward);

		play = new ToolItem(toolBar, SWT.CHECK);
		play.setImage(PrismPlugin.getImageDescriptor("icons/start.gif")
				.createImage());
		play.setText("play");
		PrismPlugin.getDefault().addWidget(contextKeyPrefix + ".play", play);

		pause = new ToolItem(toolBar, SWT.PUSH);
		pause.setImage(PrismPlugin.getImageDescriptor("icons/pause.gif")
				.createImage());
		PrismPlugin.getDefault().addWidget(contextKeyPrefix + ".pause", pause);

		stop = new ToolItem(toolBar, SWT.PUSH);
		stop.setImage(PrismPlugin.getImageDescriptor("icons/stop.gif")
				.createImage());
		stop.setEnabled(false);
		
		PrismPlugin.getDefault().addWidget(contextKeyPrefix + ".stop", stop);

		forward.addSelectionListener(new SelectionAdapter() {});
		backward.addSelectionListener(new SelectionAdapter() {});
		reload = new ToolItem(toolBar, SWT.PUSH);
		reload.setImage(PrismPlugin.getImageDescriptor("icons/refresh.gif")
				.createImage());
		reload.addSelectionListener(new SelectionAdapter() {
		});

		PrismPlugin.getDefault()
				.addWidget(contextKeyPrefix + ".reload", reload);
		stop.setText("pause");
		stop.addSelectionListener(viewerToolBar);
		play.addSelectionListener(viewerToolBar);
	}

	public void dispose() {
		if (null != animateThread) {
			animateThread = null;
			Thread.currentThread().interrupt();
		}
		
		animationCanvas.dispose();

		if (offScreenImage != null && !offScreenImage.isDisposed())
			offScreenImage.dispose();

		if (pointer != null && !pointer.isDisposed())
			pointer.dispose();

		clickSound.stop();
	}
	
	@Override
	public Control getControl() {
		return animationCanvas;
	}

	@Override
	public Object getInput() {
		return currentScreen;
	}

	@Override
	public ISelection getSelection() {
		return new StructuredSelection(currentScreen);
	}

	@Override
	public void setInput(final Object _input) {
		if(_input instanceof IPrismScreen)
			currentScreen = (IPrismScreen) _input;
	}

	@Override
	public void setSelection(ISelection _selection, boolean reveal) {
		if (!((StructuredSelection) _selection).getFirstElement().equals(
				currentScreen)) {
			currentScreen = (IPrismScreen) ((StructuredSelection) _selection)
					.getFirstElement();
		}
	}

	@Override
	public void refresh() {
		contentComposite.pack(true);
		contentComposite.layout(true);
		animationCanvas.pack(true);
		animationCanvas.layout(true);
		contentComposite.update();
		animationCanvas.update();		
	}
	
	private void openBalloon(IPrismAnnotation _note) {
		
		Shell _parent = animationCanvas.getShell();			
		window = new BalloonWindow(_parent, SWT.CLOSE);
		
		window.setText(_note.getText().trim());
		int x  = _note.getLocation().x;
		int y  = _note.getLocation().y;
		int xOffset = animationCanvas.getLocation().x;
		int yOffset = animationCanvas.getLocation().y;
//		display.map(_parent, _parent, point);
		window.setLocation(xOffset + x,yOffset + y);
		window.open();
	}
	
	public void pauseAnimation() {
		synchronized (animateThread) {
			play.setSelection(false);
			stop.setEnabled(false);
			paused = Boolean.TRUE;
			animateThread.notifyAll();
		}
	}
	public void playAnimation() {
		if (null == animateThread
				|| !animateThread.getState().equals(Thread.State.WAITING)) {
			stop.setEnabled(true);
			paused = Boolean.FALSE;
			startAnimation();
		} else {
			synchronized (animateThread) {
				play.setEnabled(false);
				stop.setEnabled(true);
				paused = Boolean.TRUE;
				animateThread.notifyAll();
			}
		}
	}
	
	SelectionAdapter viewerToolBar = new SelectionAdapter() {
		public void widgetSelected(final SelectionEvent e) {
			String controlItem = ((ToolItem)e.widget).getText();
			if(controlItem.equals("pause"))
				pauseAnimation();
			else if(controlItem.equals("play"))
				playAnimation();
		}
	};
}
